package com.hlkj.warboot.configurer.util;

import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;


public class RSAUtils3 {
	private static final Logger logger = LoggerFactory.getLogger(RSAUtils3.class);
	public static final String KEY_ALGORITHM = "RSA";
	public static final String SIGNATURE_ALGORITHM = "SHA1WithRSA";
	private static final String PUBLIC_KEY = "RSAPublicKey";
	private static final String PRIVATE_KEY = "RSAPrivateKey";
	private static final int MAX_ENCRYPT_BLOCK = 117;
	private static final int MAX_DECRYPT_BLOCK = 128;
	// 小白接口的公钥
	public static final String XB_PUBLICKEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCXqR6rzbEHqDYZby/9s9+psWvYdsYIvcGVBSHDlZlwCQu+T+Retu4aIkLWaF737gwCCxLsoBGY6EKf9Cf0G1IpTLRaKM8VmNGYD/niwA9hD4ykom3wu7tNaPACbfmuYJp5JfJ1YI/zI5SHGPo4h3sAbsi8Le0jumbty065hghhmwIDAQAB";
	public static final String XB_PRIVATEKEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAJepHqvNsQeoNhlvL/2z36mxa9h2xgi9wZUFIcOVmXAJC75P5F627hoiQtZoXvfuDAILEuygEZjoQp/0J/QbUilMtFoozxWY0ZgP+eLAD2EPjKSibfC7u01o8AJt+a5gmnkl8nVgj/MjlIcY+jiHewBuyLwt7SO6Zu3LTrmGCGGbAgMBAAECgYEAgitb8eXX/lR4KphuPnj2jbWEdQRssO/9iSQgeLicO7bn5262+jxUXQXvDAwFBxPAJrjOg15X/D/Nf3CWIkSY3RfAx/zdWZCscBvLgUbbjmvrztXLwMT0kjkBN41hDsSd0aMbG0hMLIfUenzoh0g7jweBch4Udpzk5J/iaN8d2RECQQDkt2T2/4CPWyty0L9KmnHIhrutyco87aAxuvXIthxT+aZnBXIT8LgcSytpXiyPFYYMd5lEmU7JwCd0U0l3YNP9AkEAqcCTJ/lw+6Lk6GbDyKEMHZtfxyCe5XPCb1MxhBVk7lxT7e93/hTWLQK7iQCdyNC0oihjLzPclGlrO2p7PKdjdwJADfPaJu9DSnuHVQPDB6wQUOlXPazXt4vPf/kl0U66v6y1KAe/A9RlhuRXC6CBG2F2wf/xy6uGkOw1+/SwwKWZiQJAbt4CfmIxA3hhTtQHXNqqIhAfXtuUS8HuJG1OcrjSYcdVXZpAYWbUdzNIrnMDmmuM/jeoh+S0VQ4A5h5mfLfKgwJBAN0wagjWqpidU05ZkB5HzxxhcsebAggZ3PcTV1nZVqho/npCX1R38GeUhr9H0bGpxUbFbVCMdTlkEmwFz21cPVc=";

	public RSAUtils3() {
	}

	public static void main(String[] args) throws Exception {
//		Map<String, Object> map = RSAUtils3.genKeyPair();
//		String publicKey = RSAUtils3.getPublicKey(map);
//		String privateKey = RSAUtils3.getPrivateKey(map);
//		System.out.println(privateKey);
//		System.out.println(publicKey);

		String one = "{\"timeStamp\":\"202011171408431041\",\"busiDataReq\":{\"D9\":\"1\",\"D8\":\"1\",\"D7\":\"1\",\"busType\":\"1\",\"orderType\":\"1\",\"remark\":\"测试测试测试\",\"D6\":\"1\",\"D5\":\"1\",\"D4\":\"1\",\"T1\":\"20200710235959\",\"T3\":\"20200711235959\",\"T2\":\"20200712235959\",\"phoneNo\":\"18013896707\",\"T4\":\"20200714235959\",\"orderNo\":\"12345678test\",\"Sign\":\"bjteltest\",\"D2\":\"1\",\"D3\":\"1\"}}";
		String two = "{\"timeStamp\":\"202011171408431042\",\"busiDataReq\":{\"D9\":\"1\",\"D8\":\"1\",\"D7\":\"1\",\"busType\":\"1\",\"orderType\":\"2\",\"remark\":\"测试测试测试\",\"D6\":\"1\",\"D5\":\"1\",\"D4\":\"1\",\"T1\":\"20200710235959\",\"T3\":\"20200711235959\",\"T2\":\"20200712235959\",\"phoneNo\":\"18013896707\",\"T4\":\"20200714235959\",\"orderNo\":\"12345678test\",\"Sign\":\"bjteltest\",\"D2\":\"1\",\"D3\":\"1\"}}";
		String three = "{\"timeStamp\":\"202011171408431043\",\"busiDataReq\":{\"D9\":\"1\",\"D8\":\"1\",\"D7\":\"1\",\"busType\":\"1\",\"orderType\":\"3\",\"remark\":\"测试测试测试\",\"D6\":\"1\",\"D5\":\"1\",\"D4\":\"1\",\"T1\":\"20200710235959\",\"T3\":\"20200711235959\",\"T2\":\"20200712235959\",\"phoneNo\":\"18013896707\",\"T4\":\"20200714235959\",\"orderNo\":\"12345678test\",\"Sign\":\"bjteltest\",\"D2\":\"1\",\"D3\":\"1\"}}";
		String four = "{\"timeStamp\":\"202011171408431044\",\"busiDataReq\":{\"D9\":\"1\",\"D8\":\"1\",\"D7\":\"1\",\"busType\":\"1\",\"orderType\":\"4\",\"remark\":\"测试测试测试\",\"D6\":\"1\",\"D5\":\"1\",\"D4\":\"1\",\"T1\":\"20200710235959\",\"T3\":\"20200711235959\",\"T2\":\"20200712235959\",\"phoneNo\":\"18013896707\",\"T4\":\"20200714235959\",\"orderNo\":\"12345678test\",\"Sign\":\"bjteltest\",\"D2\":\"1\",\"D3\":\"1\"}}";

        // 私钥加密字符串
        String str = RSABase64URLEncodeByPriK(XB_PRIVATEKEY,four);
        System.out.println(str);

        // 公钥解密字符串
        String str1ByPublicKey = URLDecodeBase64RSAByPubK(XB_PUBLICKEY, str);
        System.out.println(str1ByPublicKey);
        // 公钥加密字符串
        String str2ByPublicKey = RSABase64URLEncodeByPubK(XB_PUBLICKEY, str1ByPublicKey);
        System.out.println(str2ByPublicKey);
	}

	public static Map<String, Object> genKeyPair() throws Exception {
		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
		keyPairGen.initialize(1024);
		KeyPair keyPair = keyPairGen.generateKeyPair();
		RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
		RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
		Map<String, Object> keyMap = new HashMap(2);
		keyMap.put("RSAPublicKey", publicKey);
		keyMap.put("RSAPrivateKey", privateKey);
		return keyMap;
	}

	public static String sign(byte[] data, String privateKey) throws Exception {
		byte[] keyBytes = Base64.decode(privateKey);
		PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
		Signature signature = Signature.getInstance("SHA1WithRSA");
		signature.initSign(privateK);
		signature.update(data);
		return Base64.encode(signature.sign());
	}

	public static String sign(byte[] data, PrivateKey privateKey) throws Exception {
		Signature signature = Signature.getInstance("SHA1WithRSA");
		signature.initSign(privateKey);
		signature.update(data);
		return Base64.encode(signature.sign());
	}

	public static PrivateKey fileToPrivateKey(String privateKeyFile) {
		File key = new File(privateKeyFile);

		try {
			FileInputStream is = new FileInputStream(key);
			FileChannel channel = is.getChannel();
			byte[] buffer = new byte[is.available()];
			channel.read(ByteBuffer.wrap(buffer));
			byte[] keyBytes = Base64.decode(new String(buffer));
			PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
			return privateK;
		} catch (Throwable var9) {
			logger.error("fileToPrivateKey catch Throwable", var9);
			return null;
		}
	}

	public static PublicKey fileToPublicKey(String publicKeyFile) {
		logger.info("publicKeyFile path is " + publicKeyFile);
		File cert = new File(publicKeyFile);

		try {
			FileInputStream is = new FileInputStream(cert);
			FileChannel channel = is.getChannel();
			byte[] buffer = new byte[is.available()];
			channel.read(ByteBuffer.wrap(buffer));
			byte[] keyBytes = Base64.decode(new String(buffer));
			X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			PublicKey publicK = keyFactory.generatePublic(keySpec);
			return publicK;
		} catch (Throwable var9) {
			logger.error("fileToPublicKey catch Throwable", var9);
			return null;
		}
	}

	public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
		byte[] keyBytes = Base64.decode(publicKey);
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PublicKey publicK = keyFactory.generatePublic(keySpec);
		Signature signature = Signature.getInstance("SHA1WithRSA");
		signature.initVerify(publicK);
		signature.update(data);
		return signature.verify(Base64.decode(sign));
	}

	public static boolean verify(byte[] data, PublicKey publicKey, String sign) throws Exception {
		Signature signature = Signature.getInstance("SHA1WithRSA");
		signature.initVerify(publicKey);
		signature.update(data);
		return signature.verify(Base64.decode(sign));
	}

	public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception {
		byte[] keyBytes = Base64.decode(privateKey);
		PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		cipher.init(2, privateK);
		int inputLen = encryptedData.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offSet = 0;

		for (int i = 0; inputLen - offSet > 0; offSet = i * 128) {
			byte[] cache;
			if (inputLen - offSet > 128) {
				cache = cipher.doFinal(encryptedData, offSet, 128);
			} else {
				cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
			}

			out.write(cache, 0, cache.length);
			++i;
		}

		byte[] decryptedData = out.toByteArray();
		out.close();
		return decryptedData;
	}

	public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception {
		byte[] keyBytes = Base64.decode(publicKey);
		X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		Key publicK = keyFactory.generatePublic(x509KeySpec);
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		cipher.init(2, publicK);
		int inputLen = encryptedData.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offSet = 0;

		for (int i = 0; inputLen - offSet > 0; offSet = i * 128) {
			byte[] cache;
			if (inputLen - offSet > 128) {
				cache = cipher.doFinal(encryptedData, offSet, 128);
			} else {
				cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
			}

			out.write(cache, 0, cache.length);
			++i;
		}

		byte[] decryptedData = out.toByteArray();
		out.close();
		return decryptedData;
	}

	public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
		byte[] keyBytes = Base64.decode(publicKey);
		X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		Key publicK = keyFactory.generatePublic(x509KeySpec);
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		cipher.init(1, publicK);
		int inputLen = data.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offSet = 0;

		for (int i = 0; inputLen - offSet > 0; offSet = i * 117) {
			byte[] cache;
			if (inputLen - offSet > 117) {
				cache = cipher.doFinal(data, offSet, 117);
			} else {
				cache = cipher.doFinal(data, offSet, inputLen - offSet);
			}

			out.write(cache, 0, cache.length);
			++i;
		}

		byte[] encryptedData = out.toByteArray();
		out.close();
		return encryptedData;
	}

	public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception {
		byte[] keyBytes = Base64.decode(privateKey);
		PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		cipher.init(1, privateK);
		int inputLen = data.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offSet = 0;

		for (int i = 0; inputLen - offSet > 0; offSet = i * 117) {
			byte[] cache;
			if (inputLen - offSet > 117) {
				cache = cipher.doFinal(data, offSet, 117);
			} else {
				cache = cipher.doFinal(data, offSet, inputLen - offSet);
			}

			out.write(cache, 0, cache.length);
			++i;
		}

		byte[] encryptedData = out.toByteArray();
		out.close();
		return encryptedData;
	}

	public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {
		Key key = (Key) keyMap.get("RSAPrivateKey");
		return Base64.encode(key.getEncoded());
	}

	public static String getPublicKey(Map<String, Object> keyMap) throws Exception {
		Key key = (Key) keyMap.get("RSAPublicKey");
		return Base64.encode(key.getEncoded());
	}

	/**
	 * 根据 私钥加密
	 * @param privateKey
	 * @param content
	 * @return
	 * @throws Exception
	 */
	public static String RSABase64URLEncodeByPriK(final String privateKey,String content) throws Exception {
		byte[] bytes = RSAUtils3.encryptByPrivateKey(content.getBytes(), privateKey);
		String str = Base64.encode(bytes);
		str = URLEncoder.encode(str, "UTF-8");
		return str;
	}

	/**
	 * 根据私钥解密，指定字符编码
	 */
	public static String URLDecodeBase64RSAByPriK(final String privateKey,String content,String charset) throws Exception {
		String str = URLDecoder.decode(content, charset);
		byte[] bytes = RSAUtils3.decryptByPrivateKey(Base64.decode(str), privateKey);
		return new String(bytes,charset);
	}

	/**
	 * 根据公钥解密
	 * @param publicKey
	 * @param content
	 * @return
	 * @throws Exception
	 */
	public static String URLDecodeBase64RSAByPubK(final String publicKey,String content) throws Exception {
		String str = URLDecoder.decode(content, "UTF-8");
		byte[] bytes = RSAUtils3.decryptByPublicKey(Base64.decode(str), publicKey);
		return new String(bytes);
	}

	/**
	 * 根据 公钥加密
//	 * @param privateKey
	 * @param content
	 * @return
	 * @throws Exception
	 */
	public static String RSABase64URLEncodeByPubK(final String publicKey,String content) throws Exception {
		byte[] bytes = RSAUtils3.encryptByPublicKey(content.getBytes("UTF-8"), publicKey);
		String str = Base64.encode(bytes);
		str = URLEncoder.encode(str, "UTF-8");
		return str;
	}
}
